
package com.hlkj.pay.app.merchant.ext.impl.dffpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.core.type.TypeReference;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.DffScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.constant.DffPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.constant.DffPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.DffPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.rsp.OrdeCreateDataRsp;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.rsp.ResponseBody;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.req.HttpRequest;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.rsp.HttpResponse;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.dto.req.OrderCreateReq;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.utils.DffPayBase64;
import com.hlkj.pay.app.merchant.ext.impl.dffpay.utils.HttpUtils;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.common.ICommonAppConfigService;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 主扫统一下单 用户扫支付码
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = DffPayExtConstant.PAY)
public class DffPayScanPayOrderExtPt extends DffPaySceneCommonPayOrder implements DffScenePayOrderExtPt {

    private final ICommonAppConfigService commonAppConfigService;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
        // 配置转换
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        DffPayConfig dffPayConfig = getPayConfig(channelConfig, channelPayOrderContext.getMerchantAppChannelDO());
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        try {
            PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
            OrderCreateReq bodyReq = new OrderCreateReq();
            bodyReq.setSappId(dffPayConfig.getSappId());
            bodyReq.setSubMchid(dffPayConfig.getSubMchId());
            bodyReq.setOutOrderId(payOrderDO.getPayOrderNo());
            bodyReq.setSubject(payOrderDO.getSubject());
            bodyReq.setAmount(MerchantUtils.YuanToFen(payOrderDO.getAmount()));
            bodyReq.setPayType("ALIPAY");
            bodyReq.setNotifyUrl(channelPayOrderContext.getNotifyUrl());
            bodyReq.setOrderType(0);
            bodyReq.setProdType(getPayType(payWayDO));
            bodyReq.setDataType(getDataType(payWayDO));
            bodyReq.setSuccessUrl(channelPayOrderContext.getRedirectUrl());
            bodyReq.setUserIp(payOrderDO.getClientIp());
            bodyReq.setExpireTime(DateUtils.dateToString(payOrderDO.getExpiredTime(), DatePattern.NORM_DATETIME_PATTERN));
            String bodyJson = JsonUtils.toJsonString(bodyReq);
            String body = Base64.getEncoder().encodeToString(bodyJson.getBytes(StandardCharsets.UTF_8));

            HttpRequest request = createRequest(body, dffPayConfig);
            String url = domain(channelPayOrderContext.isTest()) + DffPayConstant.TRADE_CREATE;
            log.info("东方付下单req参数:{}", bodyJson);
            String response = HttpUtils.post(url, request);
            log.info("东方付下单返回参数:{}", response);

            HttpResponse ordeRsp = JsonUtils.parseObject(response, HttpResponse.class);
            if ("200".equals(ordeRsp.getCode())) {
                ResponseBody<OrdeCreateDataRsp> rspBody = JsonUtils.parseObject(DffPayBase64.decode(ordeRsp.getBizStr()), new TypeReference<ResponseBody<OrdeCreateDataRsp>>() {
                });
                log.info("东方付下单返回消息体:{}", rspBody);
                if (!rspBody.isSuccess()) {
                    String respDesc = rspBody.getMsg();
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    if (StringUtils.hasText(respDesc)) {
                        channelPayOrderContext.setRemark(respDesc);
                    } else {
                        channelPayOrderContext.setRemark("东方付下单返回错误信息为空,错误码为:" + rspBody.getCode());
                    }
                } else {
                    channelPayOrderContext.setPayInfo(rspBody.getData().getOrderStr());
                    if ("APP".equals(getPayType(payWayDO))) {
                        channelPayOrderContext.setPayDataType("data");
                    } else {
                        channelPayOrderContext.setPayDataType("pay_url");
                    }
                    channelPayOrderContext.setInsOrderNo(rspBody.getData().getOrderId());
                }
            } else {
                String respDesc = ordeRsp.getMsg();
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("东方付下单查询返回错误信息为空,错误码为:" + ordeRsp.getCode());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("东方付下单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("东方付下单请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (payType) {
            case ALIPAY:
                switch (scenePayType) {
                    case WAP:
                    case H5:
                        return "WAP";
                    case MINI_APP:
                    case APP:
                        return "APP";
                    case PC:
                        return "PCSITE";
//                    case JSAPI:
//                        return "JSAPI";
//                    case QR:
//                        return "NATIVE";
                }
        }
        return "";
    }

    private String getDataType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (payType) {
            case ALIPAY:
                switch (scenePayType) {
                    case H5:
                    case WAP:
                    case PC:
                        return "URL";
//                    case APP:
//                        return "APP";
//                    case JSAPI:
//                        return "JSAPI";
//                    case QR:
//                        return "NATIVE";
                }
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }

}
